#ifndef __UDPSERVER_HPP__
#define __UDPSERVER_HPP__
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <cstring>
#include "Log.hpp"
#include "InetAddr.hpp"

namespace wxd
{
    const int default_sockfd = -1;
    using server_task_t = std::function<std::string(std::string)>;

    class UdpServer
    {
    private:
        // 默认方法：Echo
        std::string Echo(const std::string &message)
        {
            return message;
        }
        // 方法：返回[ip : port]信息
        std::string GetInfo(sockaddr_in s_addr_in)
        {
            InetAddrTrans addr_trans(s_addr_in);
            std::string ip = addr_trans.Ip();
            std::string port = std::to_string(addr_trans.Port());
            std::string addr_info = "[" + ip + " : " + port + "] #";
            return addr_info;
        }

    public:
        UdpServer(u_int16_t port, server_task_t func)
            : _sockfd(default_sockfd), _port(port), _func(func)
        {
        }
        // 初始化服务器
        void Init()
        {
            // 创建套接字
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if (_sockfd < 0)
            {
                LOG(LogLevel::FATAL) << "创建Socket失败！";
                exit(1);
            }
            LOG(LogLevel::INFO) << "创建Socket成功: sockfd = " << _sockfd;

            // 绑定信息到套接字
            // 填充sockaddr_in结构
            // struct sockaddr_in local_info;
            // //清空sockaddr_in
            // bzero(&local_info,sizeof(local_info));
            // local_info.sin_family = AF_INET;
            // //local_info.sin_addr.s_addr = inet_addr(_ip.c_str());
            // local_info.sin_addr.s_addr = INADDR_ANY;
            // local_info.sin_port = htons(_port);

            struct sockaddr_in local_info = InetAddrTrans(_port)();

            int n = bind(_sockfd, (sockaddr *)&local_info, sizeof(local_info));
            if (n < 0)
            {
                LOG(LogLevel::FATAL) << "绑定失败！";
                exit(1);
            }
            LOG(LogLevel::INFO) << "绑定成功！port: " << ntohs(local_info.sin_port);
        }

        // 服务器启动后，要一直死循环提供服务
        void Start()
        {
            while (true)
            {
                // 接收消息
                char message[1024];

                struct sockaddr_in peer;
                socklen_t peer_len = sizeof(peer);

                int msg_len = recvfrom(_sockfd, message, sizeof(message) - 1, 0, (sockaddr *)&peer, &peer_len);
                message[msg_len] = 0;
                if (msg_len < 0)
                {
                    LOG(LogLevel::ERROR) << "收消息出错！";
                    continue;
                }
                // 获取ip+port前缀
                std::string info = GetInfo(peer);
                // 此时已经收到消息
                LOG(LogLevel::DEBUG) << "收到"<<info<< message;
                // 调用外部传来的方法
                std::string send_message = _func(message);
                int send_len = sendto(_sockfd, send_message.c_str(), send_message.size(), 0, (sockaddr *)&peer, peer_len);

                if (send_len < 0)
                {
                    LOG(LogLevel::ERROR) << "收消息出错！";
                    continue;
                }
            }
        }

    private:
        int _sockfd; // 文件描述符
        u_int16_t _port;
        // std::string _ip; // 方便查看
        server_task_t _func; // 用于接收外部传来的方法
    };
}

#endif